
package de.justphil.tcg.tcgandroidclient.gui;

import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import de.justphil.tcg.tcgandroidclient.R;
import de.justphil.tcg.tcgandroidclient.config.Config;
import de.justphil.tcg.tcgandroidclient.content.DH;
import de.justphil.tcg.tcgandroidclient.content.TCGContentAdapter;
import de.justphil.tcg.tcgandroidclient.content.TCGUM;
import de.justphil.tcg.tcgandroidclient.content.sqlite.SqliteCardInstance;
import de.justphil.tcg.tcgandroidclient.content.view.ViewCard;
import de.justphil.tcg.tcgandroidclient.util.StringTools;
import de.justphil.tcg.tcgandroidclient.util.TCGLog;
import android.app.ListActivity;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class DeckCreatorAct extends ListActivity {
	
	public static final int VIEW_MODE_REPOSITORY = 1;
	public static final int VIEW_MODE_DECK = 2;
	public static final String EXTRA_VIEW_MODE = "viewMode";
	private ListView listView;
	private TCGContentAdapter contentAdapter;
	private ContentObserver repositoryObserver;
	private ContentObserver deckObserver;
	private long deckId;
	
	public void onCreate(Bundle icicle) {
	
		super.onCreate(icicle);
		contentAdapter = new TCGContentAdapter(this);
		listView = getListView();
		listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
	
		Uri uri = getIntent().getData();
		if (DH.UM.match(uri) == TCGUM.URI_DECK) {
			MenuInflater inflater = getMenuInflater();
			inflater.inflate(R.menu.deck_creator_deck_menu, menu);
			return true;
		}
		else if (DH.UM.match(uri) == TCGUM.URI_CARD_INSTANCES) {
			MenuInflater inflater = getMenuInflater();
			inflater.inflate(R.menu.deck_creator_repository_menu, menu);
			return true;
		}
		else {
			TCGLog.e(new Object[] {
					"Unsupported Uri: ", uri }, new Exception());
			return false;
		}
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
	
		switch (item.getItemId()) {
			case R.id.menu_save:
				save();
				break;
			case R.id.menu_create:
				create();
				break;
			case R.id.menu_discard:
				discard();
				break;
			case R.id.menu_clear_selection:
				clear();
				break;
			default:
				return super.onOptionsItemSelected(item);
		}
		return true;
	}

	@Override
	protected void onStart() {
	
		super.onStart();
		// Intent intent = new Intent(DeckCreatorAct.this, RESTUpdateService.class);
		// intent.putExtra(RESTUpdateService.EXTRA_CLEAR_CACHE, true);
		// startService(intent);
	}
	
	@Override
	protected void onResume() {
	
		super.onResume();
		updateArrayAdapter();
		if (DH.UM.match(getIntent().getData()) == TCGUM.URI_DECK) {
			deckId = TCGUM.getLongId(1, getIntent().getData());
			checkDeckCards(deckId);
		}
	}
	
	@Override
	protected void onStop() {
	
		super.onStop();
	}
	
	@Override
	protected void onPause() {
	
		// TODO Auto-generated method stub
		super.onPause();
		contentAdapter.unregisterContentObserver(getRepositoryObserver());
		contentAdapter.unregisterContentObserver(getDeckObserver());
	}
	
	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
	
		super.onListItemClick(l, v, position, id);
	}

	private ContentObserver getRepositoryObserver() {
	
		if (repositoryObserver == null) {
			final Lock lock = new ReentrantLock();
			final Thread[] timer = new Thread[1];
			repositoryObserver = new ContentObserver(new Handler()) {
				
				@Override
				public void onChange(boolean selfChange) {
				
					lock.lock();
					if (timer[0] == null || !timer[0].isAlive()) {
						timer[0] = new Thread() {
							
							@Override
							public void run() {
							
								try {
									sleep(100);
								}
								catch (InterruptedException ignored) {
								}
								new Handler(getMainLooper()).post(new Runnable() {
									
									@Override
									public void run() {
									
										updateArrayAdapter();
									}
								});
							}
						};
						timer[0].start();
						updateArrayAdapter();
					}
					else {
						TCGLog.v(new Object[] {
							"Skipping update." });
					}
					lock.unlock();
				}
			};
		}
		return repositoryObserver;
	}
	
	@SuppressWarnings("unchecked")
	private ArrayAdapter<ViewCard> getArrayAdapter() {
	
		if (getListAdapter() == null) {
			setListAdapter(new ArrayAdapter<ViewCard>(this,
					android.R.layout.simple_list_item_multiple_choice));
		}
		return (ArrayAdapter<ViewCard>) getListAdapter();
	}
	
	// public ArrayAdapter<ViewCard> createArrayAdapter() {
	//
	// List<SqliteCardInstance> cardInstances =
	// contentAdapter.readCardInstances(getRepositoryObserver());
	// List<ViewCard> cards = new ArrayList<ViewCard>();
	// for (SqliteCardInstance cardInstance : cardInstances) {
	// ViewCard card =
	// new ViewCard(contentAdapter, getRepositoryObserver(), cardInstance.getId(),
	// cardInstance.getType());
	// cards.add(card);
	// }
	// ArrayAdapter<ViewCard> adapter =
	// new ArrayAdapter<ViewCard>(this, android.R.layout.simple_list_item_multiple_choice,
	// android.R.id.text1, cards);
	// return adapter;
	// }
	private void updateArrayAdapter() {
	
		TCGLog.i(new Object[] {
			"Updating the ArrayAdapter." });
		boolean updated = false;
		List<SqliteCardInstance> cardInstances =
				contentAdapter.readCardInstances(getRepositoryObserver());
		ArrayAdapter<ViewCard> adapter = getArrayAdapter();
		adapter.setNotifyOnChange(false);
		// TODO: find better solution!
		{
			adapter.clear();
		}
		for (int i = 0; i < adapter.getCount(); i++) {
			boolean found = false;
			for (SqliteCardInstance cardInstance : cardInstances) {
				if (adapter.getItem(i).getCardId() == cardInstance.getId()) {
					found = true;
					break;
				}
			}
			if (!found) {
				ViewCard card = adapter.getItem(i);
				TCGLog.d(new Object[] {
						"Removing card ", card, "." });
				adapter.remove(card);
				updated = true;
			}
		}
		for (SqliteCardInstance cardInstance : cardInstances) {
			boolean found = false;
			for (int i = 0; i < adapter.getCount(); i++) {
				if (adapter.getItem(i).getCardId() == cardInstance.getId()) {
					found = true;
					break;
				}
			}
			if (!found) {
				TCGLog.d(new Object[] {
						"Adding card ", cardInstance, "." });
				adapter.add(new ViewCard(contentAdapter, getRepositoryObserver(), cardInstance
						.getId(), cardInstance.getType()));
				updated = true;
			}
		}
		if (updated) {
			adapter.notifyDataSetChanged();
			if (DH.UM.match(getIntent().getData()) == TCGUM.URI_DECK) {
				deckId = TCGUM.getLongId(1, getIntent().getData());
				checkDeckCards(deckId);
			}
		}
		adapter.setNotifyOnChange(true);
	}

	private ContentObserver getDeckObserver() {
	
		if (deckObserver == null) {
			HandlerThread thread = new HandlerThread(StringTools.getString(new Object[] {
				"DeckObserverThread" }), Thread.MAX_PRIORITY);
			thread.start();
			deckObserver = new ContentObserver(new Handler(thread.getLooper())) {
				
				@Override
				public void onChange(boolean selfChange) {
				
					// checkDeckCards(deckId);
				}
			};
		}
		return deckObserver;
	}
	
	private void checkDeckCards(long deckId) {
	
		long[] cardIds = contentAdapter.readDeckToCards(deckId, getDeckObserver());
		TCGLog.i(new Object[] {
				"Checking ", cardIds.length, " cardIds for deck ", deckId, "!" });
		boolean found;
		/* first uncheck all */
		for (int pos = 0; pos < listView.getCount(); pos++) {
			listView.setItemChecked(pos, false);
		}
		/* check deck */
		for (int i = 0; i < cardIds.length; i++) {
			found = false;
			for (int pos = 0; pos < listView.getCount(); pos++) {
				long id = ((ViewCard) listView.getItemAtPosition(pos)).getCardId();
				if (id == cardIds[i]) {
					listView.setItemChecked(pos, true);
					found = true;
					break;
				}
			}
			if (!found) {
				TCGLog.w(new Object[] {
						"The cardId ", cardIds[i], " of deck ", deckId,
						" could not be found in the repository!" });
			}
		}
	}
	
	private void create() {
	
		// TODO
		if (requireCheckedNumber()) {
			// contentAdapter.addDeck(id, name, deck)
			finish();
		}
	}
	
	private void save() {
	
		// TODO: save
		if (requireCheckedNumber()) {
			finish();
		}
	}
	
	private void discard() {
	
		// TODO discard
	}
	
	private void clear() {
	
		for (int i = 0; i < listView.getChildCount(); i++) {
			listView.setItemChecked(i, false);
		}
	}
	
	private boolean requireCheckedNumber() {
	
		int choiceCount = listView.getCheckItemIds().length;
		if (choiceCount > Config.DECK_SIZE) {
			Toast.makeText(DeckCreatorAct.this, StringTools.getString(new Object[] {
					"You selected ", choiceCount - Config.DECK_SIZE, " to many cards!" }),
					Toast.LENGTH_SHORT).show();
			return false;
		}
		else if (choiceCount < Config.DECK_SIZE) {
			Toast.makeText(DeckCreatorAct.this, StringTools.getString(new Object[] {
					"You selected ", Config.DECK_SIZE - choiceCount, " to few cards!" }),
					Toast.LENGTH_SHORT).show();
			return false;
		}
		return true;
	}
}
